/*
 * Copyright (c) 2022. CloudStar.Co.Ltd. All rights reserved.
 */

package com.longy.desensitized.util;

import com.longy.desensitized.util.annotation.SensitiveDataClass;
import com.longy.desensitized.util.annotation.SensitiveDataField;

import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Objects;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import lombok.extern.slf4j.Slf4j;

/**
 * 加密工具类
 */
@Slf4j
@Component
public class EncryptDecryptUtil {

    //密钥key
    private final static byte[] key = new byte[]{8, 71, 41, -38, 16, 66, 11, -71, 66, -107, 7, -51, -55, 103, -40, 2};
    private final static AES aes = SecureUtil.aes(key);

    public static <T> T encrypt(Field[] declaredFields, T sensitiveObject) throws IllegalAccessException {
        for (Field field : declaredFields) {
            // 取出所有被SensitiveField注解的字段
            SensitiveDataField sensitiveField = field.getAnnotation(SensitiveDataField.class);
            if (Objects.nonNull(sensitiveField)) {
                field.setAccessible(true);
                Object targetProperty = field.get(sensitiveObject);
                // 仅讨论对字符串类型的字段的加密
                if (targetProperty instanceof String) {
                    // 取得源字段值
                    String value = (String) targetProperty;
                    String valueEncrypt;
                    // 使用Base64对称加密
                    valueEncrypt = encrypt(value);
                    // 将加密完成的字段值放入待用参数对象
                    field.set(sensitiveObject, valueEncrypt);
                }
            }
        }
        return sensitiveObject;
    }


    /**
     * 判断是否是需要解密的敏感实体类
     *
     * @param object 对象
     *
     * @return boolean
     */
    public static boolean needToDecrypt(Object object) {
        Class<?> objectClass = object.getClass();
        SensitiveDataClass sensitiveData = AnnotationUtils.findAnnotation(objectClass, SensitiveDataClass.class);
        return Objects.nonNull(sensitiveData);
    }

    /**
     * 加密
     *
     * @param value 价值
     *
     * @return {@link String}
     */
    private static String encrypt(String value) {
        return aes.encryptHex(value);
    }

    /**
     * 解密对象
     *
     * @param object 对象
     *
     * @return {@link String}
     */
    public static void decryptObject(Object object) throws IllegalAccessException, InvocationTargetException {
        Field[] declaredFields = ClassUtils.getUserClass(object).getDeclaredFields();
        for (Field field : declaredFields) {
            field.setAccessible(true);
            SensitiveDataField sf = field.getAnnotation(SensitiveDataField.class);
            if (ObjectUtils.isEmpty(sf)) {
                continue;
            }
            PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(ClassUtils.getUserClass(object), field.getName());
            if (Objects.isNull(pd)) {
                continue;
            }
            Object value = pd.getReadMethod().invoke(object);
            if (Objects.isNull(value)) {
                continue;
            }
            //解密
            String valueEncrypt = decrypt(value.toString());
            // 将加密完成的字段值放入待用参数对象
            pd.getWriteMethod().invoke(object, valueEncrypt);
        }
    }

    /**
     * 解密
     *
     * @param value 价值
     *
     * @return {@link String}
     */
    public static String decrypt(String value) {
        return aes.decryptStr(value);
    }
}
